/** 
* \file GestureBase.h
*/

/******************************************************************************/
#pragma once

/******************************************************************************/
#include <windows.h>

/******************************************************************************/
enum GestureType {GT_UNKNOWN, GT_LINEAR, GT_CIRCLE, GT_HOLD, GT_TILT, GT_SHAKE};

/******************************************************************************/
#define PI		3.1415926F

#define		HI_MOUSE			0x0001
#define		HI_MOUSE_TRACK		0x0002
#define		HI_IST_SHAKE		0x0004
#define		HI_IST_TILT			0x0008

class CGestureBase;
class CGestureSet;

/// Type of callback function fired when gesture detected.
typedef void (*PDETECTEDPROC) (CGestureBase*);

/// Type of callback function fired when gesture wants to force a redraw for diagnostic purposes.
typedef void (*PREPAINTPROC) (CGestureBase*);

/******************************************************************************/
/**
* All classes which implement a particular type of gesture detection should
* derive from GestureBase.
*
* Derived classes set hHandlesInput to an OR'ed combination of HI_ constants
* to indicate which types of input they need. The main plugin DLL then passes
* the required inputs to the gesture class instances by calling the corresponding
* methods.
*
* HI_MOUSE - mouse down/up/move<BR>
* HI_MOUSE_TRACK - list of points generated by mouse movement between down and up<BR>
* HI_IST_SHAKE - accelerometer data
* HI_IST_TILT - tilt data
*/
/******************************************************************************/
class CGestureBase
{
public:
	CGestureBase ();
	virtual ~CGestureBase ();

	GestureType gtType;	///< Type of the gesture - set to GT_UNKNOWN by base class, set to actual value by derived class
	WCHAR ID [64];		///< ID string for gesture, so plugin DLL knows which gesture instance has fired
	int nHandlesInput;	///< Types of input required - see class description
	bool bShowDiagnostics;		///< TRUE to draw diagnostic information when \cref Render() is called
	CGestureSet *pSet;	///< The gesture set holding this gesture
	PDETECTEDPROC pDetectedProc;	///< Callback fired when gesture is detected (could be from a different thread)
	PREPAINTPROC pRepaintProc;	///< Callback fired when gesture wants to force a redraw for diagnostices (could be from a different thread)

	/**
	* If nHandlesInput includes HI_MOUSE then class must implement this function.
	* \param x X position of mouse
	* \param y Y position of mouse
	*/
	virtual void HandleMouseDown (int x, int y) { }

	/**
	* If nHandlesInput includes HI_MOUSE then class must implement this function.
	* \param x X position of mouse
	* \param y Y position of mouse
	*/
	virtual void HandleMouseMove (int x, int y) { }

	/**
	* If nHandlesInput includes HI_MOUSE then class must implement this function.
	* \param x X position of mouse
	* \param y Y position of mouse
	*/
	virtual void HandleMouseUp (int x, int y) { }

	/**
	* If nHandlesInput includes HI_MOUSE_TRACK then class must implement this function.
	* \param npoints Number of points in the track
	* \param ptrack Array of points describing the track
	*/
	virtual void HandleMouseTrack (int npoints, POINT *ptrack) { }

	/**
	* If nHandlesInput includes Sensor then class must implement this function.
	* Parameter values are those returned by the Sensor library.
	*/
	virtual void HandleSensor (int x, int y, int z) { }

	/**
	* Draws diagnostic data
	* \param hdc Device contect to draw into
	*/
	virtual void Render (HDC hdc) { }

protected:
	/**
	* Derived class calls this function to fire callback in plugin DLL when gesture is detected.
	*/
	void OnDetected () { if (pDetectedProc) (*pDetectedProc) (this); }

	/**
	* Derived class calls this function to fire callback in plugin DLL when gesture
	* wants to force a redraw for diagnostic purposes.
	*/
	void OnRepaint () { if (pRepaintProc) (*pRepaintProc) (this); }
};

/******************************************************************************/
/**
* Base class for describing partial regions of a gesture.
*/
/******************************************************************************/
class CGestureRegion
{
public:
	bool Crossed;	///< Set if the region has been crossed during processing (typically mouse input)

	CGestureRegion ();
	virtual ~CGestureRegion ();

	/**
	* Draws diagnostic data, if any.
	* \param hdc Device contect to draw into
	*/
	virtual void Render (HDC hdc) { }

	/**
	* Checks if region contains specified point
	* \param point Point to check
	*/
	virtual bool ContainsPoint (POINT point) {return false;}
};

/******************************************************************************/
/**
* Gesture region bounded by a number of straight lines
*/
/******************************************************************************/
class CPolyRegion: public CGestureRegion
{
private:
	static int nInstanceCount;		///< Used to allocate GDI resources shared between instances
	static HPEN hOutlinePen;		///< For drawing diagnostics
	static HBRUSH hCrossedBrush;	///< For drawing diagnostics
	static HBRUSH hNonCrossedBrush;	///< For drawing diagnostics

	int nPoints;		///< Number of vertex points
	int nNextPoint;		///< Next vertex point to be added by \ref AddPoint
	POINT *pPoints;		///< Array of vertex points

public:
	/// \param points Number of vertex points
	CPolyRegion (int points);
	~CPolyRegion ();

	/// Adds a vertex point to the array
	/// \param point Vertex point to add
	void AddPoint (POINT point);

	/// Draws outline of region, filled if region was crossed during last analysis
	/// \param hdc Device context to draw into
	void Render (HDC hdc);

	bool ContainsPoint (POINT point);
};

/******************************************************************************/
/**
* Gesture region bounded by a circle
*/
/******************************************************************************/
class CCircleRegion: public CGestureRegion
{
private:
	static int nInstanceCount;		///< Used to allocate GDI resources shared between instances
	static HPEN hOutlinePen;		///< For drawing diagnostics
	static HBRUSH hCrossedBrush;	///< For drawing diagnostics

	float fCentreX;		///< Centre of circle
	float fCentreY;		///< Centre of circle
	float fRadius;		///< Radius of circle

public:
	/// \param centre_x Centre of circle
	/// \param centre_y Centre of circle
	/// \param radius Radius of circle
	CCircleRegion (float centre_x, float centre_y, float radius);
	~CCircleRegion ();

	/// Draws outline of circle, filled if region was crossed during last analysis
	/// \param hdc Device context to draw into
	void Render (HDC hdc);

	bool ContainsPoint (POINT point);
};
